/*--------------------------------------------------------------------------------------*\
**
** seminary_window.cpp
**
** Heroes IV
** Copyright 2001, The 3DO Company
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "seminary_window.h"

#include "adaptor_handler.h"
#include "adventure_map.h"
#include "basic_dialog.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_window.h"
#include "bound_handler.h"
#include "button.h"
#include "button_cache.h"
#include "creature_array_window.h"
#include "external_string.h"
#include "format_string.h"
#include "game_replace_keywords.h"
#include "interface_help.h"
#include "player.h"
#include "replace_keywords.h"
#include "skill_button.h"
#include "skill_properties.h"
#include "standard_fonts.h"

extern t_external_string const k_hotkey_buy;
extern t_button_cache               g_ok_button;
extern t_button_cache const         k_learn_button;
extern  t_bitmap_group_cache const	k_magic_university_bitmaps( "dialog.magic_university" );

static t_external_string const k_text_seminary_name( "seminary_name.misc" );
static t_external_string const k_text_seminary_intro( "intro_university.dialog" );
static t_external_string const k_text_learned_skill( "learned_skill_university.dialog" );

const   int k_university_skill_cost   = 2000;

// -----------------------------------------------------------------
// add heroes from one array to another
// -----------------------------------------------------------------
static void copy_heroes( t_creature_array& dest, t_creature_array& source )
{
	int		i;
	t_hero* hero;

	for (i = 0; i < t_creature_array::k_size; i++)
	{
		hero = source[i].get_hero();
		// Hero or not?
		if (hero == 0)
			continue;

	    dest.add( hero );
	}
}

/*---------------------------------------------------------------------------------------*\
**
** Seminary window constructor.
**
\*---------------------------------------------------------------------------------------*/
t_seminary_window::t_seminary_window( t_creature_array* army, t_creature_array* adjacent_army, 
									  t_stationary_adventure_object const& object,
									  std::string const&				   title,
									  t_skill_list const& skills, 
									  t_window* parent )
                   : t_window( k_completely_transparent, parent ),
				     m_adventure_object( object )
{
	t_adventure_map &       map = *army->get_map();
	int						player_number = map.get_player_number();

    /*
    ** Set init. values.
    */
    m_skills = skills; 
	m_player_ptr = &map.get_player();  
	m_skill_selected = 0;
	m_selected_hero = 0;

	if ( army->get_owner_number() == player_number )
		copy_heroes( m_garrison_heroes, *army );

	if ( adjacent_army && adjacent_army->get_owner_number() == player_number )
	{
		if (m_garrison_heroes.empty())
			copy_heroes( m_garrison_heroes, *adjacent_army );
		else
			copy_heroes( m_adjacent_heroes, *adjacent_army );
	}
	create_background();
	create_rings();
	create_buttons();

	t_screen_rect           rect;
	t_text_window* text_window_ptr;

    // Add title text.
	rect = m_bitmaps_ptr->find( "text_title" )->get_rect();
	text_window_ptr= new t_text_window( get_font( rect.height()), rect, this, 
										title, t_pixel_24(0,0,0) );
	text_window_ptr->set_center_horizontal();
    
	t_screen_point	origin;

	origin = m_background->get_screen_rect().top_left();
	origin = -to_client( origin );

	rect = m_bitmaps_ptr->find( "text_dialog" )->get_rect() + origin;
	m_text = new t_text_window( get_font( 20 ), rect, m_background, "", t_pixel_24(0,0,0) );
	m_text->set_center_horizontal();

	m_garrison_hero_window->select_first();
    choose_skill( NULL, 0 );
}

// ---------------------------------------------------------------------
// create skill buttons
// ---------------------------------------------------------------------
void t_seminary_window::create_skill_buttons()
{
    // Show skill icons and text.
    t_skill			skill;
	t_screen_point	origin;
	int				i;

	origin = m_background->get_screen_rect().top_left();
	origin = -to_client( origin );
	m_skill_button_group.clear();
    for (i=0; i < k_skill_button_count; i++)
    {
        skill = m_current_skills[i];

        // Add 1 to i because we want 1-4 inclusive.
		t_screen_rect rect;

    	rect = m_bitmaps_ptr->find( format_string( "icon_%i", i+1) )->get_rect() + origin;

        create_skill_toggle_button( rect, skill, m_background, i );

    }
}

// ---------------------------------------------------------------------
// get first skill learnable by a hero
// ---------------------------------------------------------------------
t_skill t_seminary_window::get_learnable_skill( t_hero& hero, t_skill skill )
{
	// check if this would require adding a primary skill, and we're
	// already at the primary skill limit.
	t_skill_type primary_skill;

	primary_skill = get_primary_skill( skill.skill );
	if (hero.get_skill( primary_skill ) == k_mastery_none 
		&& hero.get_primary_skill_count() == k_primary_skill_limit)
		return skill;
		
	while ( !hero.can_learn( skill ) && hero.get_skill( skill.skill ) < skill.level )
	{
		std::vector<t_skill> const&	requirements = get_requirements( skill );

		int i, j;

		// for each requirement, have we used it already?
		for (i = 0; i < requirements.size(); ++i)
		{
			j = k_skill_button_count;
			while (j--)
				if ( m_current_skills[j] == requirements[i] )
				{
					// attempt to replace the other skill.
					m_current_skills[j] = get_learnable_skill( hero, m_current_skills[j] );
					if (m_current_skills[j] == requirements[i])
						break;
				}

			// if this requirement does not duplicate any existing skills,
			// switch to examining this requirement.
			if (j < 0)
			{
				skill = requirements[i];
				break;
			}
		}
		if (i == requirements.size())
			break;
	}
	return skill;
}

// ---------------------------------------------------------------------
// select hero skills
// ---------------------------------------------------------------------
void t_seminary_window::select_skills( t_hero& hero )
{
	int		i;

	// mark basic skill catagories
	assert( m_skills.size() == k_skill_button_count );
	for (i =0 ; i < k_skill_button_count; ++i)
	{
		m_current_skills[i].skill = m_skills[i];
		m_current_skills[i].level = k_mastery_basic;
	}

	// mark previously learned skills
	int							university_id = m_adventure_object.get_global_id();
	t_university_diploma const* diploma = hero.get_diploma( university_id );

	if (diploma != 0)
	{
		for (i = 0; i < k_university_class_limit; ++i)
			if (diploma->skills[i].level != k_mastery_none)
				m_current_skills[i] = diploma->skills[i];
	}

	for (i = 0; i < k_skill_button_count; ++i)
	{
		// find the first prerequisite that we can learn (or this skill, if we can learn it).
		m_current_skills[i] = get_learnable_skill( hero, m_current_skills[i] );
		m_skill_text[i]->set_text( get_name( m_current_skills[i] ) );
	}
}

void t_seminary_window::create_background()
{
	t_bitmap_layer const*   layer;
	t_window*               window;
	t_screen_point          origin(0,0);

	m_bitmaps_ptr = k_magic_university_bitmaps.get();
	m_skill_frames = k_skill_frames.get();
	m_player_funds = m_player_ptr->get_funds()[k_gold];
	m_current_cost = 0;

	/*
    ** Create background
    */
	layer = m_bitmaps_ptr->find( "top" );
	window = new t_bitmap_layer_window( layer, origin, this );
	layer = m_bitmaps_ptr->find( "left" );
	window = new t_bitmap_layer_window( layer, origin, this );
	layer = m_bitmaps_ptr->find( "bottom" );
	window = new t_bitmap_layer_window( layer, origin, this );
	layer = m_bitmaps_ptr->find( "right" );
	window = new t_bitmap_layer_window( layer, origin, this );

	layer = m_bitmaps_ptr->find( "background" );
	m_background = new t_bitmap_layer_window( layer, origin, this );
}

void t_seminary_window::create_rings()
{
	t_screen_point origin;

	origin = -m_background->get_screen_rect().top_left();
	origin = to_client( origin );

	/*
    ** Create hero selection portraits. 
    */
	t_screen_rect			rect;
	t_bitmap_layer const*	layer;
	t_window*				window;

	rect = m_bitmaps_ptr->find("hero_ring_portraits")->get_rect() + origin;

	if (m_adjacent_heroes.empty())
	{
		layer = m_bitmaps_ptr->find( "single_ring_background" );
		window = new t_bitmap_layer_window( layer, origin, m_background );
	    m_garrison_hero_window = new t_creature_array_window( layer->get_rect().top_left() + origin,
													&m_garrison_heroes, 
													t_creature_array_window::k_single_row,
													0, m_background, false, false );
		m_visiting_hero_window = 0;
	
	}
	else
	{
		t_screen_point point;

		layer = m_bitmaps_ptr->find( "double_ring_background" );
		window = new t_bitmap_layer_window( layer, origin, m_background );
		point = rect.top_left();
	    m_garrison_hero_window = new t_creature_array_window( point,
													&m_garrison_heroes, 
													t_creature_array_window::k_top_row,
													0, m_background, false, false );

		point.y += m_garrison_hero_window->get_frame_height();
		m_visiting_hero_window = new t_creature_array_window( point, &m_adjacent_heroes, 
						t_creature_array_window::k_bottom_row, 0,
						m_background, false, false );
		m_visiting_hero_window->set_select_handler( bound_handler( *this, 
													&t_seminary_window::hero_selection_change ) );
		m_visiting_hero_window->set_allow_drags( false );
		m_visiting_hero_window->move_before( m_garrison_hero_window );
		m_visiting_hero_window->link_selection( m_garrison_hero_window );
	}

	m_garrison_hero_window->set_select_handler( bound_handler( *this, 
												&t_seminary_window::hero_selection_change ) );
	m_garrison_hero_window->set_allow_drags( false );
}

void t_seminary_window::create_buttons()
{
	t_screen_point origin;
	t_help_block const&		help = get_help_block( "shared" );

	origin = m_background->get_screen_rect().top_left();
	origin = -to_client( origin );

	/*
    ** Add the gold cost text - cost of skill upgrade is 2000
    */
	t_screen_rect rect;

	rect = m_bitmaps_ptr->find( "text_gold" )->get_rect() + origin;
	m_cost_window_ptr = new t_text_window( get_font( rect.height() ), rect, m_background, 
										   format_string( "%i", m_current_cost ), 
										   t_pixel_24(0,0,0) );
	m_cost_window_ptr->set_drop_shadow( true, t_pixel_24(200,200,200) );
	m_cost_window_ptr->set_justification( k_justify_center );

    /*
    ** Create buttons.
    */
	t_button            *button_ptr;

    /*
    ** Add buy button.
    */
	rect = m_bitmaps_ptr->find( "purchase_button" )->get_rect();
	m_buy_button_ptr = new t_button( k_learn_button.get(), rect.top_left(), this );
	m_buy_button_ptr->set_click_handler( bound_handler( *this, &t_seminary_window::buy_clicked ) );
  set_help( m_buy_button_ptr, help, "learn" );	

	// Create close button
	rect = m_bitmaps_ptr->find( "close_button" )->get_rect();
	button_ptr = new t_button( g_ok_button.get(), rect.top_left(), this );
	button_ptr->set_click_handler( bound_handler( *this, &t_seminary_window::close_clicked ));
  set_help( button_ptr , help, "ok" );

    /*
    ** Set the position and display the window.
    */
	t_screen_rect parent_rect = get_parent()->get_client_rect();
    
	rect = m_bitmaps_ptr->get_rect();
	rect += (parent_rect.size() - rect.size()) / 2;
	init( rect );

	int i;

	assert( m_skills.size() == k_skill_button_count );
	for (i = 0; i < k_skill_button_count; ++i)
	{
		m_current_skills[i].skill = m_skills[i];
		m_current_skills[i].level = k_mastery_basic;
	}

	std::string text;

    for ( i=0; i < k_skill_button_count; i++)
    {
        // Add skill text.
		t_text_window_ptr text_window_ptr;

		text = get_name( m_current_skills[i] );

    	rect = m_bitmaps_ptr->find( format_string( "text_icon_%i", i + 1) )->get_rect() + origin;
    	text_window_ptr = new t_text_window( get_font( rect.height()/2 ), rect, m_background, 
											 text, t_pixel_24(0,0,0));
    	text_window_ptr->set_center_horizontal();
    	text_window_ptr->set_drop_shadow( false );
		m_skill_text[i] = text_window_ptr;
    }

	create_skill_buttons();
}

void t_seminary_window::enable_learn( bool arg )
{
	if (arg)
		m_current_cost = k_university_skill_cost;
	else
		m_current_cost = 0;

	m_cost_window_ptr->set_text( format_string( "%i", m_current_cost ) );

    /*
    ** Disable buy button if player doesn't have sufficient funds.
    */
	if ((m_current_cost > m_player_funds) || (m_current_cost == 0)) 
    {
	    m_buy_button_ptr->enable (false);
    }
    else
    {
	    m_buy_button_ptr->enable (true);
    }
}

void t_seminary_window::set_text()
{
	t_skill		target_skill( m_skills[m_skill_selected], k_mastery_basic );
	t_skill		skill = m_current_skills[m_skill_selected];
	std::string text;

	// set the correct error / message text
	if (m_selected_hero == 0)
	{
		text = m_adventure_object.get_text( "university_no_heroes" );
		enable_learn( false );
	}
	else
	{
		if ( m_selected_hero->get_skill( skill.skill ) >= skill.level )
		{
			int university_id = m_adventure_object.get_global_id();
			t_university_diploma const* diploma = m_selected_hero->get_diploma( university_id );

			if (diploma == 0 || diploma->skills[m_skill_selected] != skill)
				text = m_adventure_object.get_text( "university_skill_known" );
			else
				text = m_adventure_object.get_text( "university_learned_here" );
			enable_learn( false );
		}
		else if ( m_player_ptr->get_funds()[k_gold] < k_university_skill_cost )
		{
			text = m_adventure_object.get_text( "university_no_money" );
			enable_learn( false );
		}
		else if ( m_selected_hero->get_skill( get_primary_skill( skill.skill ) ) == k_mastery_none
				  && m_selected_hero->get_primary_skill_count() == k_primary_skill_limit)
		{
			text = m_adventure_object.get_text( "university_brain_full" );
			enable_learn( false );
		}
		else if ( !m_selected_hero->can_learn( skill ))
		{
			std::vector<t_skill> const& requirements = get_requirements( skill );
			
			text = m_adventure_object.get_text( "university_not_qualified" );
			text = replace_keywords( text, "%required_skill_name",
									 get_name( requirements.front() ) );
			enable_learn( false );
		}
		else if ( skill != target_skill )
		{
			text = m_adventure_object.get_text( "university_alternate_skill" );
			enable_learn( true );
		}
		else
		{
			text = m_adventure_object.get_text( "university_legal_skill" );
			enable_learn( true );
		}
		text = replace_keywords( text, m_selected_hero );
	}
	text = replace_keywords( text, "%skill_name", get_name( skill ) );
	text = replace_keywords( text, "%advanced_skill_name", get_name( target_skill )); 
	m_text->set_text( text );
}

/*
** Create skill toggle buttons
*/
void t_seminary_window::create_skill_toggle_button( t_screen_rect skill_rect, t_skill skill, 
												    t_window* parent_window, int id)
{
	t_toggle_button*		toggle_button_ptr;
	t_button_handler        button_handler;

    /*
    ** Create toggle button shell - enable radio button.
    */
	toggle_button_ptr = new t_toggle_button( skill_rect.top_left(), parent_window, true );

	create_skill_button( toggle_button_ptr, skill, m_skill_frames );

	button_handler = add_2nd_argument( bound_handler( *this, &t_seminary_window::choose_skill ), id);
	toggle_button_ptr->set_click_handler( button_handler );

	if (m_skill_buttons[id].get() != 0)
		m_skill_buttons[id]->close();

	m_skill_buttons[id] = toggle_button_ptr;
	m_skill_button_group.add( toggle_button_ptr );
}

void t_seminary_window::hero_selection_change( t_creature_array_window* window, int selection )
{
	if (selection < 0)
		return;

	t_creature_array& army = *window->get_army();

	m_selected_hero = army[selection].get_hero();
	select_skills( *m_selected_hero );
	create_skill_buttons();
	choose_skill( 0, m_skill_selected );
}

/*-------------------------------------------------------------------*\
** Clicked on a skill radio button.
\*-------------------------------------------------------------------*/
void t_seminary_window::choose_skill( t_button* button, int id )
{
    t_skill                 skill;

    /*
    ** If button is NULL, routine is called explicitly, so don't check for it.
    */
    if (button)
    {
    	if (!(button->is_pressed()))
            return;
    }
    /*
    ** Set selected graphic manually because we're calling this routine explicitly.
    */
    else
    {
	    m_skill_button_group.select( id );
    }

    /*
    ** Now check which heroes are eligible to buy selected skill.
    */
	m_skill_selected = id;
	set_text();
}


/*-------------------------------------------------------------------*\
** Clicked on the close button.
\*-------------------------------------------------------------------*/
void t_seminary_window::buy_clicked( t_button* button )
{
    t_skill     skill = m_current_skills[m_skill_selected];

	m_player_ptr->spend( k_gold, m_current_cost );
	m_player_funds = m_player_ptr->get_funds()[k_gold];

    std::string text = replace_keywords( k_text_learned_skill, "%skill_name", 
												get_name( skill ) );
	text = replace_keywords( text, m_selected_hero );
	

    t_basic_dialog*	result_dialog_ptr;
	t_screen_rect	parent_rect = get_parent()->get_client_rect();
    
    result_dialog_ptr = new t_basic_dialog;

    result_dialog_ptr->set_text( text );
    result_dialog_ptr->add_skill( skill );

	/*
    ** Add the hero portrait windows
    */
	result_dialog_ptr->add_creature( *m_selected_hero, false );
    result_dialog_ptr->add_ok_button();
    
    result_dialog_ptr->open( true );
    result_dialog_ptr->run_modal();

	int university_id = m_adventure_object.get_global_id();

	m_selected_hero->learn_skill( skill, true );
	m_selected_hero->add_diploma( university_id, m_skill_selected, skill );
    /*
    ** Reset hero windows.
    */
    choose_skill (NULL, m_skill_selected);
}

/*-------------------------------------------------------------------*\
** Clicked on the close button.
\*-------------------------------------------------------------------*/
void t_seminary_window::close_clicked( t_button* button )
{
	close();
}
